package Hxw3DEngine.asset.parsers
{
	import flash.net.*;
	import flash.utils.*;
	
	public class MD2Parser extends ParserBase
	{
		
		private var textures:Array;
		
		public var vectexs:Dictionary;
		
		public function MD2Parser(textureType:String = "jpg", ignoreTexturePath:Boolean = true)
		{
			_textureType = textureType;
			_ignoreTexturePath = ignoreTexturePath;
			textures = new Array;
			vectexs = new Dictionary;
		}
		
		public static var FPS:int = 6;
		
		private var _clipNodes:Dictionary = new Dictionary(true);
		private var _parsedHeader:Boolean;
		private var _parsedUV:Boolean;
		private var _parsedFaces:Boolean;
		private var _parsedFrames:Boolean;
		
		private var _ident:uint;
		private var _version:uint;
		private var _skinWidth:uint;
		private var _skinHeight:uint;
		//private var _frameSize : uint;
		private var _numSkins:uint;
		private var _numVertices:uint;
		private var _numST:uint;
		private var _numTris:uint;
		//private var _numGlCmds : uint;
		private var _numFrames:uint;
		private var _offsetSkins:uint;
		private var _offsetST:uint;
		private var _offsetTris:uint;
		private var _offsetFrames:uint;
		//private var _offsetGlCmds : uint;
		private var _offsetEnd:uint;
		
		private var _uvIndices:Vector.<Number>;
		public var _indices:Vector.<uint>;
		private var _vertIndices:Vector.<Number>;
		private var _indexMap:Dictionary = new Dictionary(true);
		
		// the current subgeom being built
		public var _uvs:Vector.<Number>;
		public var _finalUV:Vector.<Number>;
		
		private var _materialNames:Vector.<String>;
		private var _textureType:String;
		private var _ignoreTexturePath:Boolean;
		private var timer:Timer;
		
		private var materialFinal:Boolean = false;
		private var geoCreated:Boolean = false;
		
		
		protected var _lastFrameTime:Number;
		
		override public function proceedParsing():Boolean
		{
			if (!startedParsing) {
				startedParsing = true;
				targetData.position = 0;
			}
			
			while (hasTime()) {
				if (!_parsedHeader) {
					targetData.endian = Endian.LITTLE_ENDIAN;
					parseHeader();
					parseMaterialNames();
				}
				
				else if (!_parsedUV)
					parseUV();
				
				else if (!_parsedFaces)
					parseFaces();
				
				else if (!_parsedFrames)
					parseFrames();
				else if (geoCreated)
					return true;
				
				else if (!geoCreated) {
					geoCreated = true;
				}
			}
			
			return false;
		}
		
		//md2文件头
		private function parseHeader():void
		{
			_ident = targetData.readInt();
			_version = targetData.readInt();
			_skinWidth = targetData.readInt();
			_skinHeight = targetData.readInt();
			//skip _frameSize
			targetData.readInt();
			_numSkins = targetData.readInt();
			_numVertices = targetData.readInt();
			_numST = targetData.readInt();
			_numTris = targetData.readInt();
			//skip _numGlCmds
			targetData.readInt();
			_numFrames = targetData.readInt();
			_offsetSkins = targetData.readInt();
			_offsetST = targetData.readInt();
			_offsetTris = targetData.readInt();
			_offsetFrames = targetData.readInt();
			//skip _offsetGlCmds
			targetData.readInt();
			_offsetEnd = targetData.readInt();
			
			_parsedHeader = true;
		}
		
		//解析纹理
		private function parseMaterialNames():void
		{
			var url:String;
			var name:String;
			var extIndex:int;
			var slashIndex:int;
			_materialNames = new Vector.<String>();
			targetData.position = _offsetSkins;
			
			var regExp:RegExp = new RegExp("[^a-zA-Z0-9\\_\/.]", "g");
			for (var i:uint = 0; i < _numSkins; ++i) {
				name = targetData.readUTFBytes(64);
				name = name.replace(regExp, "");
				extIndex = name.lastIndexOf(".");
				if (_ignoreTexturePath)
					slashIndex = name.lastIndexOf("/");
				if (name.toLowerCase().indexOf(".jpg") == -1 && name.toLowerCase().indexOf(".png") == -1) {
					name = name.substring(slashIndex + 1, extIndex);
					url = name + "." + _textureType;
				} else
					url = name;
				
				_materialNames[i] = name;
				// only support 1 skin TODO: really?
				if (textures.length == 0)
					textures.push(url);
					//addDependency(name, new URLRequest(url));
			}
			
			if (textures.length > 0)
				trace(0);
				//_mesh.material.name = _materialNames[0];
			else
				materialFinal = true;
		
		}
		
		//UV坐标
		private function parseUV():void
		{
			var j:uint;
			
			_uvs = new Vector.<Number>(_numST*2);
			targetData.position = _offsetST;
			for (var i:uint = 0; i < _numST; i++) {
				_uvs[j++] = targetData.readShort()/_skinWidth;
				_uvs[j++] = targetData.readShort()/_skinHeight;
			}
			
			_parsedUV = true;
		}
		
		private function parseFaces():void
		{
			var a:uint, b:uint, c:uint, ta:uint, tb:uint, tc:uint;
			var i:uint;
			
			_vertIndices = new Vector.<Number>();
			_uvIndices = new Vector.<Number>();
			_indices = new Vector.<uint>();
			
			targetData.position = _offsetTris;
			
			for (i = 0; i < _numTris; i++) {
				//collect vertex indices
				a = targetData.readUnsignedShort();
				b = targetData.readUnsignedShort();
				c = targetData.readUnsignedShort();
				
				//collect uv indices
				ta = targetData.readUnsignedShort();
				tb = targetData.readUnsignedShort();
				tc = targetData.readUnsignedShort();
				
				addIndex(a, ta);
				addIndex(b, tb);
				addIndex(c, tc);
			}
			
			var len:uint = _uvIndices.length;
			_finalUV = new Vector.<Number>(len*2, true);
			
			for (i = 0; i < len; ++i) {
				_finalUV[uint(i << 1)] = _uvs[uint(_uvIndices[i] << 1)];
				_finalUV[uint(((i << 1) + 1))] = _uvs[uint((_uvIndices[i] << 1) + 1)];
			}
			
			_parsedFaces = true;
		}
		
		private function addIndex(vertexIndex:uint, uvIndex:uint):void
		{
			var index:int = findIndex(vertexIndex, uvIndex);
			
			if (index == -1) {
				_indices.push((_indexMap[vertexIndex] ||= new Dictionary(true))[uvIndex] = _vertIndices.length);
				_vertIndices.push(vertexIndex);
				_uvIndices.push(uvIndex);	
			} else
				_indices.push(index);
		}
		
		private function findIndex(vertexIndex:uint, uvIndex:uint):int
		{
			if (_indexMap[vertexIndex] != null && _indexMap[vertexIndex][uvIndex] != null)
				return _indexMap[vertexIndex][uvIndex];
			return -1;
		}
		
		private var testVectexs:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>;
		private function parseFrames():void
		{
			var sx:Number, sy:Number, sz:Number;
			var tx:Number, ty:Number, tz:Number;
			var vertLen:uint = _vertIndices.length;
			var fvertices:Vector.<Number>;
			var tvertices:Vector.<Number>;
			var i:uint, j:int, k:uint;
			var name:String = "";
			targetData.position = _offsetFrames;
			for (i = 0; i < _numFrames; i++) {
				tvertices = new Vector.<Number>();
				fvertices = new Vector.<Number>(vertLen*3, true);
				sx = targetData.readFloat();
				sy = targetData.readFloat();
				sz = targetData.readFloat();
				tx = targetData.readFloat();
				ty = targetData.readFloat();
				tz = targetData.readFloat();
				name = readFrameName();
				for (j = 0; j < _numVertices; j++, targetData.position++)
					tvertices.push(sx*targetData.readUnsignedByte() + tx, sy*targetData.readUnsignedByte() + ty, sz*targetData.readUnsignedByte() + tz);
				k = 0;
				for (j = 0; j < vertLen; j++) {
					fvertices[k++] = tvertices[uint(_vertIndices[j]*3)];
					fvertices[k++] = tvertices[uint(_vertIndices[j]*3 + 2)];
					fvertices[k++] = tvertices[uint(_vertIndices[j]*3 + 1)];
				}
				testVectexs.push(fvertices);
				if(!vectexs[name]) vectexs[name] = new Vector.<Vector.<Number>>;
				vectexs[name].push(fvertices);
			}
			_parsedFrames = true;
		}
		
		private function readFrameName():String
		{
			var name:String = "";
			var k:uint = 0;
			for (var j:uint = 0; j < 16; j++) {
				var ch:uint = targetData.readUnsignedByte();
				
				if (uint(ch) > 0x39 && uint(ch) <= 0x7A && k == 0)
					name += String.fromCharCode(ch);
				
				if (uint(ch) >= 0x30 && uint(ch) <= 0x39)
					k++;
			}
			return name;
		}
		
		public function get numVertices():uint 
		{
			return _finalUV.length/2;
		}
		
	}
}

